﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Passwords.Models;
using Passwords.Services;

namespace PasswordsService
{
    /// <summary>
    /// Interface to sync passwords between devices, e.g. from windows phone to client app and vice versa.
    /// </summary>
    /// <remarks>
    /// Order of Methods:
    /// 
    ///  A) Backup
    ///    1xLogin -> n x SendPassword -> 1xLogout
    ///    
    /// B) Restore
    ///  1xGetBackups -> to retreive a list of available backups to select
    ///  1xLogin -> 1xSelectBackup -> n x SendPassword -> 1 x GetPasswordCount -> m x GetPassword -> Logout
    ///  
    /// C) Sync
    /// 1xLogin -> n x SendPassword -> 1 x GetPasswordCount -> mx GetPassword -> Logout
    ///  
    /// Note that the phone (or device) must delete the password after calling SendPassword() if the return value is UpdateMode.Deleted.
    /// </remarks>
    [ServiceContract]
    public interface IPasswordSyncService
    {

        [OperationContract]
        int Version();

        /// <summary>
        /// Just to test whether the service is alive.
        /// </summary>
        [OperationContract]
        string Ping(string value);

        /// <summary>
        /// Login the service.
        /// </summary>
        /// <param name="deviceId">A unique guid which is always the same for a device.</param>
        /// <param name="sessionId">A unique guid which is created by the device for each login and does not change until Logout.</param>
        /// <param name="hash">The hash code for the password which was typed in on the client.</param>
        /// <param name="mode">Specifies whether to backup, restore or sync data.</param>
        /// <returns>True if login succeeds, otherwise false.</returns>
        [OperationContract]
        bool Login(Guid deviceId, Guid sessionId, byte[] hash, SyncMode mode);

        [OperationContract]
        bool LoginUnknown(Guid deviceId, Guid sessionId, SyncMode mode);


        /// <summary>
        /// Logs a device out and notifies that a client guid is no longer valid.
        /// </summary>
        /// <param name="sessionId">Guid to invalidate.</param>
        [OperationContract(IsOneWay = true)]
        void Logout(Guid client);

        /// <summary>
        /// Gets all passwords from the previously specified backup
        /// </summary>
        /// <param name="sessionId">Id of the session specified on <see cref="Login()"/>.</param>
        /// <returns>Number of available passwords.</returns>
        /// <remarks>
        ///  Before passwords can be counted, <see cref="Login()"/> and then <see cref="SelectBackup()"/> must be called once before.
        /// </remarks>
        [OperationContract]
        int GetPasswordCount(Guid sessionId);

        /// <summary>
        /// Gets a particular password from a previously specified backup.
        /// </summary>
        /// <param name="sessionId">Id of the session specified on <see cref="Login()"/>.</param>
        /// <param name="index">Index of the password to select.</param>
        /// <returns>PasswordContract of the specified password with encrypted data.</returns>
        /// <remarks>
        ///  Before any password can be reveived from backup, <see cref="Login()"/> and then <see cref="GetPasswordCount()"/> must be called once before.
        /// </remarks>
        [OperationContract]
        PasswordContract GetPassword(Guid sessionId, int index);

        /// <summary>
        /// Sends a backup to the service to backup.
        /// </summary>
        /// <param name="sessionId">Id of the session specified on <see cref="Login()"/>.</param>
        /// <param name="password">PasswordContract with encrypted password.</param>
        /// <returns></returns>
        /// <remarks>
        ///  Before any password can be sent to backup, <see cref="Login()"/> must be called once before.
        /// </remarks>
        [OperationContract]
        UpdateMode SendPassword(Guid sessionId, PasswordContract password);

        /// <summary>
        /// Deletes a password from the backup.
        /// </summary>
        /// <param name="sessionId">Id of the session specified on <see cref="Login()"/>.</param>
        /// <param name="password">Password to delete.</param>
        /// <returns></returns>
        /// <remarks>
        ///  Before any password can be deleted from backup, <see cref="Login()"/> must be called once before.
        /// </remarks>
        [OperationContract]
        UpdateMode DeletePassword(Guid sessionId, PasswordContract password);

        /// <summary>
        /// Gets all backups for a specific device.
        /// </summary>
        /// <param name="deviceId">Unique id of the device for which to get the backup (can be ignored).</param>
        /// <param name="passwordHash">
        /// The hash code of the password that was entered at the device
        /// The device expects passwords to be transfered with the password matching the hash.
        /// </param>
        /// <returns>All available backups. Usually those backups which match the specified password.</returns>
        [OperationContract]
        BackupDataContract[] GetBackups(Guid deviceId, byte[] passwordHash);


        /// <summary>
        /// Selects one of the backups which have been previously returned with <see cref="GetBackups"/>
        /// </summary>
        /// <param name="sessionId">The session id.</param>
        /// <param name="index">The index of the backup which was returned with <see cref="GetBackups"/></param>
        /// <returns>True if the backup could be selected, otherwise false.</returns>
        /// <remarks>
        ///  This method usually follows after calling <see cref="GetBackups()"/> to return a list of available backups.
        /// </remarks>
        [OperationContract]
        bool SelectBackup(Guid sessionId, int index);

        /// <summary>
        /// Currently not used.
        /// </summary>
        [OperationContract]
        byte[] GetPasswordHash(Guid sessionId);

        [OperationContract]
        CategoryContract GetCategory(Guid sessionId, int index);

        [OperationContract]
        int GetCategoryCount(Guid sessionId);


        [OperationContract]
        UpdateMode SendCategory(Guid sessionId, CategoryContract category);


        [OperationContract]
        UpdateMode DeleteCategory(Guid sessionId, CategoryContract category);

    }
}
